package com.news.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.util.Properties;

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:/config/jdbc.properties")
public class HibernateConfig implements TransactionManagementConfigurer
{
    @Value("${jdbc.driverClass}")
    private String driverClass;
    @Value("${jdbc.jdbcUrl}")
    private String jdbcUrl;
    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev()
    {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public HibernateTemplate hibernateTemplate()
    {
        return new HibernateTemplate(sessionFactory());
    }

    @Bean
    public SessionFactory sessionFactory()
    {
        LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(getDataSource());
        sessionBuilder.addProperties(getHibernateProperties());
        sessionBuilder.scanPackages("com.news");

        return sessionBuilder.buildSessionFactory();
    }

    @Bean
    public DataSource getDataSource()
    {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        try
        {
            dataSource.setDriverClass(driverClass);
            dataSource.setJdbcUrl(jdbcUrl);
            dataSource.setUser(user);
            dataSource.setPassword(password);
        }
        catch (PropertyVetoException e)
        {
            e.printStackTrace();
        }

        return dataSource;
    }

    private Properties getHibernateProperties()
    {
        Properties properties = new Properties();
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");

        //连接池配置，生产环境必须用c3p0

        //初始化时获取三个连接，取值应在minPoolSize与maxPoolSize之间。Default: 3
        properties.put("hibernate.c3p0.min_size", "5");
        //连接池中保留的最大连接数。Default: 15
        properties.put("hibernate.c3p0.max_size", "20"); //最大连接数
        //当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
        properties.put("hibernate.c3p0.acquire_increment", "3");
        //每60秒检查所有连接池中的空闲连接。Default: 0
        properties.put("hibernate.c3p0.idle_test_period", "1800");

        //JDBC的标准参数，用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
        //属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
        //如果maxStatements与maxStatementsPerConnection均为0，则缓存被关闭。Default: 0
        properties.put("hibernate.c3p0.max_statements", "100");

        //最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0
        properties.put("hibernate.c3p0.timeout", "2500");

        return properties;
    }

    @Autowired
    @Bean(name = "transactionManager")
    public HibernateTransactionManager getTransactionManager()
    {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory());
        return transactionManager;
    }

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager()
    {
        return getTransactionManager();
    }
}